// 8.12.2010 - Gregor Radziszewski
//Usage:
//Do 
//
//# cram zap
//
//to load the bitfile ramtest.bit onto the FPGA. Remember that you must
//take the bitfile from this version set. The original ramtest.v has been altered.
//After the zapping of the FPGA you do 
//
//# cram kugelfisch.jpg
//
//to load the picture of the nice Kugelfisch onto the SDRAM.
//cram will return you the amount of bytes read in the SDRAM. Assure that the amount
//of bytes is the same as the size of the file. 
//Remember the size of the file and use
//
//#cread 23134
//
//to read 23134 bytes from the SDRAM to the file 'out.jpg'.
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <fstream>
#include <stdio.h>
#include "okFrontPanelDLL.h"




long writeSDRAM(okCUsbFrontPanel *dev, unsigned char *b, long b_size){
	long c;
    
	// Reset FIFOs
	dev->SetWireInValue(0x00, 0x0004);
	dev->UpdateWireIns();
	dev->SetWireInValue(0x00, 0x0000);
	dev->UpdateWireIns();

	// Enable SDRAM write memory transfers
	dev->SetWireInValue(0x00, 0x0002);
	dev->UpdateWireIns();
	c = dev->WriteToPipeIn(0x80, b_size, b);
	
        // Flush write-fifo to SDRAM
        dev->SetWireInValue(0x00, 0x0010);
        dev->UpdateWireIns();
    
	// Disable SDRAM write memory transfers
	dev->SetWireInValue(0x00, 0x0000);
	dev->UpdateWireIns();

	return c;
}

long readSDRAM(okCUsbFrontPanel *dev, unsigned char *b, long b_size){
    long c;

    
    // Reset SDRAM-page address to zero
    dev->SetWireInValue(0x00, 0x0008);    //We manually set the rowaddr in ramtest.v to zero
    dev->UpdateWireIns();                 //This means we start reading the zeroth page first
                                          //Then rowaddr is incremented by ramtest.v to read 
                                          //the next page
    // Enable SDRAM read memory transfers
    dev->SetWireInValue(0x00, 0x0001);
    dev->UpdateWireIns();
    c = dev->ReadFromPipeOut(0xA0, b_size, b);
    
    // Disable SDRAM read memory transfers
    dev->SetWireInValue(0x00, 0x0000);
    dev->UpdateWireIns();

    return c;
}








int main(int argc, char *argv[]){

  char dll_date[32], dll_time[32];
  okCUsbFrontPanel *dev;
  long c;


  printf("PI3-Diamond - SDRAM-Testapplikation.\n");
  if (FALSE == okFrontPanelDLL_LoadLib(NULL)) {
    printf("FrontPanel DLL could not be loaded.\n");
    return(-1);
  }
  okFrontPanelDLL_GetVersion(dll_date, dll_time);
  printf("FrontPanel DLL loaded.  Built: %s  %s\n", dll_date, dll_time);
  

  dev = new okCUsbFrontPanel;
  if (okCUsbFrontPanel::NoError != dev->OpenBySerial()) {
    delete dev;
    printf("Device could not be opened.  Is one connected?\n");
    return(-1);
  }
	

  // Configure the PLL appropriately
  //dev->LoadDefaultPLLConfiguration();
  
  // Get some general information about the XEM.
  printf("Device firmware version: %d.%d\n", dev->GetDeviceMajorVersion(), dev->GetDeviceMinorVersion());
  printf("Device serial number: %s\n", dev->GetSerialNumber().c_str());
  printf("Device ID string: %s\n", dev->GetDeviceID().c_str());

  // Any arguments given ?
  if(argc < 2)
          return 0; //no
   
   
  if(!strcmp(argv[1], "zap")){
     printf("Zapping the FPGA.\n");
   // Download the configuration file.
     if (okCUsbFrontPanel::NoError != dev->ConfigureFPGA("ramtest.bit")) {
		printf("FPGA configuration failed ! Maybe there is no bitfile ?\n");
		delete dev;
		return -1;		
     }
     delete dev;
     return 0;
  }
  
	// Check for FrontPanel support in the FPGA configuration.
  if (!dev->IsFrontPanelEnabled()) {
		printf("FrontPanel support is not enabled.\n");
		delete dev;
		return -1;
  }

  printf("FrontPanel support is enabled.\n");
   
    if(argc < 3)
          return 0; //no
  
  if(!strcmp(argv[1], "write")){
    // Now we get the testfile
    // ate - open and seek to end immediately after opening
    std::ifstream file(argv[2], std::ios_base::binary | std::ios_base::ate | std::ios_base::in); 
    if(!file.is_open()){
        printf("File %s not found !\n", argv[2]);
        return -1;
    }
    int filesize = file.tellg();
    char* buffer = new char[filesize];
    file.seekg(0, std::ios_base::beg);
    file.read(buffer, filesize);


    printf("Wrting %s to FPGA-SDRAM.\n", argv[2]);
    c = writeSDRAM(dev, (unsigned char*) buffer, filesize);
    printf("%d bytes written.", c);


    delete dev;
    file.close();
    return 0;
  }
  
    if(!strcmp(argv[1], "read")){
        long count = atoi(argv[2]);
        printf("Reading %d bytes from the FPGA-SDRAM.\n", count);
        char* buffer = new char[count];
        c = readSDRAM(dev, (unsigned char*) buffer, count);

        
        std::ofstream file("out.jpg", std::ios_base::binary); 
        if(!file.is_open()){
            printf("Could not open output-file !\n");
            return -1;
        }
        file.write(buffer, c);
        printf("%d bytes read into file out.jpg .", c);


        delete dev;
        file.close();
        return 0;
   }
}
